<template>
  <div
    ref="menu"
    :class="[commonClass.menu, 'rd-editor-contextmenu', customClass]"
    :style="{
      left: style.left + 'px',
      top: style.top + 'px',
      minWidth: style.minWidth + 'px',
      zIndex: style.zIndex
    }"
    v-if="visible"
    @contextmenu="e => e.preventDefault()"
  >
    <div class="rd-editor-contextmenu-body">
      <template v-for="(item, index) of menus">
        <template v-if="!item.hidden">
          <div class="rd-editor-contextmenu-item rd-editor-contextmenu-item-disabled" :class="[commonClass.menuItem, commonClass.unclickableMenuItem]" :key="index" v-if="item.disabled">
            <div class="rd-editor-contextmenu-item-icon" v-if="hasIcon">
              <i :class="item.icon" v-if="item.icon"></i>
            </div>
            <div class="rd-editor-contextmenu-item-label">{{ item.label }}</div>
            <div class="rd-editor-contextmenu-item-info">{{ item.info }}</div>
            <div class="rd-editor-contextmenu-item-expand-icon"></div>
          </div>
          <div
            class="rd-editor-contextmenu-item rd-editor-contextmenu-item-available"
            :class="[commonClass.menuItem, item.children && item.children.length > 0 ? commonClass.unclickableMenuItem : commonClass.clickableMenuItem, activeSubmenu.index === index ? 'rd-editor-contextmenu-item-expand' : null]"
            :key="index"
            @mouseenter="$event => enterItem($event, item, index)"
            @click="itemClick(item, !(item.children && item.children.length > 0))"
            v-else
          >
            <div class="rd-editor-contextmenu-item-icon" v-if="hasIcon">
              <i :class="item.icon" v-if="item.icon"></i>
            </div>
            <div class="rd-editor-contextmenu-item-label">{{ item.label }}</div>
            <div class="rd-editor-contextmenu-item-info">{{ item.info }}</div>
            <div class="rd-editor-contextmenu-item-expand-icon">
              <span v-if="item.children && item.children.length > 0">></span>
            </div>
          </div>
          <div v-if="item.divided" :key="'contextmenu-item-divided-' + index" class="rd-editor-contextmenu-item-divided">
            <div></div>
          </div>
        </template>
      </template>
    </div>
  </div>
</template>

<script>
import Vue from 'vue'
import { SUBMENU_X_OFFSET, SUBMENU_Y_OFFSET, SUBMENU_OPEN_TREND_LEFT, SUBMENU_OPEN_TREND_RIGHT, COMPONENT_NAME, TARGET_DOM_CLASS_NAME } from './constant'
export default {
  name: COMPONENT_NAME,
  data() {
    return {
      commonClass: {
        menu: null,
        menuItem: null,
        clickableMenuItem: null,
        unclickableMenuItem: null
      },
      activeSubmenu: {
        index: null,
        instance: null
      },
      menus: [],
      position: {
        x: 0,
        y: 0,
        width: 0,
        height: 0
      },
      style: {
        left: 0,
        top: 0,
        zIndex: 2,
        minWidth: 150
      },
      customClass: null,
      visible: false,
      hasIcon: false,
      openTrend: SUBMENU_OPEN_TREND_RIGHT
    }
  },
  mounted() {
    this.visible = true
    for (let item of this.menus) {
      if (item.icon) {
        this.hasIcon = true
        break
      }
    }
    this.$nextTick(() => {
      const windowWidth = document.documentElement.clientWidth
      const windowHeight = document.documentElement.clientHeight
      const menu = this.$refs.menu
      const menuWidth = menu.offsetWidth
      const menuHeight = menu.offsetHeight

      ;(this.openTrend === SUBMENU_OPEN_TREND_LEFT ? this.leftOpen : this.rightOpen)(windowWidth, windowHeight, menuWidth)

      this.style.top = this.position.y
      if (this.position.y + menuHeight > windowHeight) {
        if (this.position.height === 0) {
          this.style.top = this.position.y - menuHeight
        } else {
          this.style.top = windowHeight - menuHeight
        }
      }
    })
  },
  methods: {
    leftOpen(windowWidth, windowHeight, menuWidth) {
      this.style.left = this.position.x - menuWidth
      this.openTrend = SUBMENU_OPEN_TREND_LEFT
      if (this.style.left < 0) {
        this.openTrend = SUBMENU_OPEN_TREND_RIGHT
        if (this.position.width === 0) {
          this.style.left = 0
        } else {
          this.style.left = this.position.x + this.position.width
        }
      }
    },
    rightOpen(windowWidth, windowHeight, menuWidth) {
      this.style.left = this.position.x + this.position.width
      this.openTrend = SUBMENU_OPEN_TREND_RIGHT
      if (this.style.left + menuWidth > windowWidth) {
        this.openTrend = SUBMENU_OPEN_TREND_LEFT
        if (this.position.width === 0) {
          this.style.left = windowWidth - menuWidth
        } else {
          this.style.left = this.position.x - menuWidth
        }
      }
    },
    enterItem(e, item, index) {
      if (!this.visible) {
        return
      }
      if (this.activeSubmenu.instance) {
        if (this.activeSubmenu.index === index) {
          return
        } else {
          this.activeSubmenu.instance.close()
          this.activeSubmenu.instance = null
          this.activeSubmenu.index = null
        }
      }
      if (!item.children) {
        return
      }
      const menuItemClientRect = e.target.getBoundingClientRect()
      const SubmenuConstructor = Vue.component(COMPONENT_NAME)
      this.activeSubmenu.index = index
      this.activeSubmenu.instance = new SubmenuConstructor()
      this.activeSubmenu.instance.menus = item.children
      this.activeSubmenu.instance.openTrend = this.openTrend
      this.activeSubmenu.instance.commonClass = this.commonClass
      this.activeSubmenu.instance.position = {
        x: menuItemClientRect.x + SUBMENU_X_OFFSET,
        y: menuItemClientRect.y + SUBMENU_Y_OFFSET,
        width: menuItemClientRect.width - 2 * SUBMENU_X_OFFSET,
        height: menuItemClientRect.width
      }
      this.activeSubmenu.instance.style.minWidth = typeof item.minWidth === 'number' ? item.minWidth : this.style.minWidth
      this.activeSubmenu.instance.style.zIndex = this.style.zIndex
      this.activeSubmenu.instance.customClass = typeof item.customClass === 'string' ? item.customClass : this.customClass
      this.activeSubmenu.instance.$mount()
      document.getElementsByClassName(TARGET_DOM_CLASS_NAME)[0].append(this.activeSubmenu.instance.$el)
    },
    itemClick(item, isExecute) {
      if (!isExecute) {
        return
      }
      if (!this.visible) {
        return
      }
      if (item && !item.disabled && !item.hidden && typeof item.onClick === 'function') {
        return item.onClick()
      }
    },
    close() {
      this.visible = false
      if (this.activeSubmenu.instance) {
        this.activeSubmenu.instance.close()
      }
      this.$nextTick(() => {
        this.$destroy()
      })
    }
  }
}
</script>
